package com.sinodata.bsm.cicp.collector.net.trap;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import org.apache.log4j.Logger;
import org.snmp4j.CommandResponder;
import org.snmp4j.CommandResponderEvent;
import org.snmp4j.MessageDispatcherImpl;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.mp.MPv1;
import org.snmp4j.mp.MPv2c;
import org.snmp4j.mp.MPv3;
import org.snmp4j.security.SecurityModels;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.TcpAddress;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.MultiThreadedMessageDispatcher;
import org.snmp4j.util.ThreadPool;

import com.sinodata.bsm.cicp.collector.net.trap.impl.TrapProcess;
import com.sinodata.bsm.cicp.util.SystemContext;

/**
 * 本类用于监听代理进程的Trap 信息
 *
 *
 *
 */
public class MultiThreadedTrapReceiver implements CommandResponder {
    private Logger logger = Logger.getLogger(MultiThreadedTrapReceiver.class.getName());

    private MultiThreadedMessageDispatcher dispatcher;
    private Snmp snmp = null;
    private Address listenAddress;
    private ThreadPool threadPool;
    //    private EventSent eventSent = new EventSent();
    private List<TrapProcess> trapProcesses = new ArrayList();

    public MultiThreadedTrapReceiver() {
        // BasicConfigurator.configure();
    }

    private void init() throws UnknownHostException, IOException {
        this.getClasses();
        threadPool = ThreadPool.create("Trap ", 2);
        dispatcher = new MultiThreadedMessageDispatcher(threadPool, new MessageDispatcherImpl());
        String port = (String) SystemContext.getProperty("TrapPort");
        //		String port = "162";
        listenAddress = GenericAddress.parse(System.getProperty("snmp4j.listenAddress", "0.0.0.0/" + port));
        TransportMapping transport;
        // 对TCP与UDP协议进行处理
        if (listenAddress instanceof UdpAddress) {
            transport = new DefaultUdpTransportMapping((UdpAddress) listenAddress);
        } else {
            transport = new DefaultTcpTransportMapping((TcpAddress) listenAddress);
        }
        snmp = new Snmp(dispatcher, transport);
        snmp.getMessageDispatcher().addMessageProcessingModel(new MPv1());
        snmp.getMessageDispatcher().addMessageProcessingModel(new MPv2c());
        snmp.getMessageDispatcher().addMessageProcessingModel(new MPv3());
        USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
        SecurityModels.getInstance().addSecurityModel(usm);
        snmp.listen();
    }

    public void run() {
        try {
            init();
            snmp.addCommandResponder(this);
            logger.info("Start to monitor the trap!");
        } catch (Throwable ex) {
            logger.error(ex);
        }
    }

    public void stop() {
        if (snmp != null) {
            try {
                snmp.close();
            } catch (IOException e) {
                logger.error("Snmp stop error ", e);
            }
        }
    }

    /**
     * 实现CommandResponder的processPdu方法, 用于处理传入的请求、PDU等信息 当接收到trap 时，会自动进入这个方法
     *
     * @param respEvnt
     */

    public void processPdu(CommandResponderEvent respEvnt) {
        if (respEvnt != null && respEvnt.getPDU() != null) {
            for (int i = 0; i < trapProcesses.size(); i++) {
                boolean flag = trapProcesses.get(i).trapProcess(respEvnt);
                if (!flag) {
                    trapProcesses.get(i).setTrapProcess(trapProcesses.get(i));
                }
            }
        }
    }

    private void loadPropertyFile(Properties prop, String filename) throws Exception {
        File file = new File(filename);
        InputStream inputStream = new FileInputStream(file);
        prop.load(inputStream);
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (Exception e) {
            }
            inputStream = null;
        }
    }

    private void getClasses() {
        TrapProcess trapProcess;
        Properties properties = new Properties();
        try {
            loadPropertyFile(properties, "conf/net/trapType.properties");
            Iterator iterator = properties.keySet().iterator();
            while (iterator.hasNext()) {
                String keyString = (String) iterator.next();
                String value = (String) properties.get(keyString);
                trapProcess = (TrapProcess) Class.forName(value).newInstance();
                trapProcesses.add(trapProcess);
            }
        } catch (Exception e) {
            logger.error(e);
        }

    }

    public static void main(String[] args) {
        MultiThreadedTrapReceiver multithreadedtrapreceiver = new MultiThreadedTrapReceiver();
        multithreadedtrapreceiver.run();
        // multithreadedtrapreceiver.getClasses();
    }

}
